package com.dq.controller.ali.pay;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.dq.ali.pay.AliPayUtils;
import com.dq.domain.subscribe.Subscribe;
import com.dq.domain.sys.user.Account;
import com.dq.exception.customException.AdminException;
import com.dq.service.AllService;
import com.dq.utils.DateUtils;
import com.dq.vo.Vo;
import com.dq.wx.pay.async.WxPayAsyncMethod;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.exception.WxPayException;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;

@RestController
@RequestMapping("/ali/pay/")
public class AliPayController extends AllService {
    private static final Logger log = LoggerFactory.getLogger(AliPayController.class);

    @Autowired
    private WxPayAsyncMethod wxPayAsyncMethod;

    @ApiOperation(value = "扫码支付: 预下单")
    @GetMapping("precreate02/{id}")
    public Vo precreate02(@PathVariable Long id) throws Exception {
        Account account = dao.get(Account.class, id);
        if(account == null) {
            throw new AdminException("记录不存在, id: " + id);
        }
        String outTradeNo = account.getOrderNo();
        // 支付金额, 单位元
        BigDecimal totalAmount = account.getPrice();
        if(totalAmount == null) {
            throw new AdminException("订单支付金额为空");
        }
        // 订单标题, STRING(256)
        String subject = outTradeNo;
        // 该笔订单允许的最晚付款时间，逾期将关闭交易
        String timeoutExpress = "2h";
        // 商品Id, trade_type=NATIVE，此参数必传。此id为二维码中包含的商品Id，商户自行定义, 类型：String(32);
        String productId = account.getUserCard().getId().toString();

        Long loginUserId = account.getUser().getId();

        // 获取 扫码 支付 需要的二维码url
        String ossQrUrl = AliPayUtils.precreate(outTradeNo, totalAmount, subject, timeoutExpress, productId, loginUserId);

        return new Vo(ossQrUrl);
    }

    @ApiOperation(value = "扫码支付: 预下单")
    @GetMapping("precreate/{orderId}")
    public Vo precreate(@PathVariable Long orderId) throws Exception {
        Subscribe subscribe = dao.get(Subscribe.class, orderId);
        if(subscribe == null) {
            throw new AdminException("订单不存在, orderId: " + orderId);
        }
        String outTradeNo = subscribe.getSubscribeNo();
        // 支付金额, 单位元
        BigDecimal totalAmount = subscribe.getServiceProject().getProjectPrice();
        if(totalAmount == null) {
            throw new AdminException("订单支付金额为空");
        }
        // 订单标题, STRING(256)
        String subject = outTradeNo;
        // 该笔订单允许的最晚付款时间，逾期将关闭交易
        String timeoutExpress = "2h";
        // 商品Id, trade_type=NATIVE，此参数必传。此id为二维码中包含的商品Id，商户自行定义, 类型：String(32);
        String productId = subscribe.getServiceProject().getId().toString();

        Long loginUserId = subscribe.getWxUser().getId();

        // 获取 扫码 支付 需要的二维码url
        String ossQrUrl = AliPayUtils.precreate(outTradeNo, totalAmount, subject, timeoutExpress, productId, loginUserId);

        return new Vo(ossQrUrl);
    }

    @ApiOperation(value = "扫码支付 异步通知")
    @PostMapping("nologin/notify")
    public String parseOrderNotifyResult(@RequestBody String xmlData) {
        // 手动处理异常, 使中间逻辑是否成功, 都返回成功, 避免一直回调, 异常在本地做记录
        try {
            log.info(">>>>  支付回调通知处理, 接收原始数据包: {}", xmlData);
            JSONObject notifyResult = JSONObject.parseObject(xmlData);
            log.info("<<<<  支付回调通知处理, 转换原始数据包: {}", notifyResult);

            Object tradeStatus = notifyResult.get("trade_status");
            if(tradeStatus != null) {
                if("TRADE_SUCCESS".equals(tradeStatus.toString()) || "TRADE_FINISHED".equals(tradeStatus.toString())) {
                    // TODO 根据自己业务场景需要构造返回对象 -------------------- begin
                    String outTradeNo = notifyResult.get("out_trade_no").toString();
                    String transactionId = notifyResult.get("trade_no").toString();
                    // 单位元 -> 分
                    Integer totalFee = Integer.parseInt(notifyResult.get("total_amount").toString())*100;
                    // 支付完成时间，格式为yyyy-MM-dd HH:mm:ss
                    String timeEnd = notifyResult.get("gmt_payment").toString();
                    long payTime = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", timeEnd).getTime();
                    String sign = notifyResult.get("sign").toString();
                    System.out.println(">>>>  支付回调通知处理, sign: "+ sign);

                    wxPayAsyncMethod.parseOrderNotifyResultAsync(outTradeNo, transactionId, totalFee, payTime, sign);
                    // TODO 根据自己业务场景需要构造返回对象 -------------------- end
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
            log.error("支付宝 支付回调通知处理 [异常], 返回支付宝成功, 本地记录; msg: {}", e.getMessage());
        }

        return WxPayNotifyResponse.success("成功");
    }

    @ApiOperation(value = "查询订单")
    @GetMapping("nologin/queryOrder/{outTradeNo}")
    public Vo queryOrder(@PathVariable String outTradeNo) throws WxPayException, AlipayApiException {
        JSONObject precreate = AliPayUtils.query(outTradeNo);

        // 是否支付成功, TRADE_SUCCESS（交易支付成功）、TRADE_FINISHED（交易结束，不可退款）
        Object tradeStatus = precreate.get("trade_status");
        if(tradeStatus != null) {
            if("TRADE_SUCCESS".equals(tradeStatus.toString()) || "TRADE_FINISHED".equals(tradeStatus.toString())) {
                // TODO 根据自己业务场景需要构造返回对象 -------------------- begin
                String transactionId = precreate.get("trade_no").toString();
                // 单位元 -> 分
                Integer totalFee = new BigDecimal(precreate.get("total_amount").toString()).multiply(new BigDecimal(100)).intValue();
                // 支付完成时间，格式为yyyy-MM-dd HH:mm:ss
                String timeEnd = precreate.get("send_pay_date").toString();
                long payTime = DateUtils.dateTime("yyyy-MM-dd HH:mm:ss", timeEnd).getTime();
                String sign = precreate.get("sign").toString();
                System.out.println(">>>>  查询订单, sign: "+ sign);

                wxPayAsyncMethod.parseOrderNotifyResultAsync(outTradeNo, transactionId, totalFee, payTime, sign);
                // TODO 根据自己业务场景需要构造返回对象 -------------------- end
            }
        }

        return new Vo(precreate);
    }

}
